﻿using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;

using Fuse8.DomainFramework.Domain;
using Fuse8.DomainFramework.Common;

namespace Fuse8.DomainFramework.BusinessService
{
    /// <summary>
    /// 
    /// </summary>
    public enum SortDirection
    {
        /// <summary>
        /// 
        /// </summary>
        Ascending = 0,
        /// <summary>
        /// 
        /// </summary>
        Descending
    }
    
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TKey"></typeparam>
    /// <typeparam name="TSortKey"></typeparam>
    public class SortableQueryLibrary<TEntity, TKey, TSortKey> : BaseQueryLibrary<TEntity, TKey>
        where TEntity : class, IEntityObject<TKey>, new()
        where TKey : IComparable<TKey>, IEquatable<TKey>
        where TSortKey : IComparable<TSortKey>
    {
        private SortableQueryLibraryProperty<TEntity, TKey, TSortKey> _sortProperty;

        /// <summary>
        /// 
        /// </summary>
        public virtual Expression<Func<TEntity, TSortKey>> SortExpression { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public SortDirection SortDirection { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public SortableQueryLibraryProperty<TEntity, TKey, TSortKey> SortProperty
        {
            get
            {
                return _sortProperty;
            }
            set
            {
                if (value != null)
                {
                    _sortProperty = value;

                    SortExpression = _sortProperty.SortExpression;
                    SortDirection = _sortProperty.SortDirection;
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public SortableQueryLibrary()
        { }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sortExpression"></param>
        public SortableQueryLibrary(Expression<Func<TEntity, TSortKey>> sortExpression)
            : this(sortExpression, SortDirection.Ascending)
        { }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sortExpression"></param>
        /// <param name="sortDirection"></param>
        public SortableQueryLibrary(Expression<Func<TEntity, TSortKey>> sortExpression, SortDirection sortDirection)
        {
            SortExpression = sortExpression;

            SortDirection = sortDirection;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sortProperty"></param>
        public SortableQueryLibrary(SortableQueryLibraryProperty<TEntity, TKey, TSortKey> sortProperty)
        {
            SortProperty = sortProperty;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="expression"></param>
        /// <returns></returns>
        public override IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> expression)
        {
            return Sort(base.Find(expression).AsQueryable());
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override IEnumerable<TEntity> FindAll()
        {
            return Sort(base.FindAll().AsQueryable());
        }

        private IQueryable<TEntity> Sort(IQueryable<TEntity> query)
        {
            Guard.ArgumentNotNull(query, "query");

            return SortExpression != null ?
                (SortDirection == SortDirection.Ascending ?
                   query.OrderBy(SortExpression) :
                   query.OrderByDescending(SortExpression)) :
                query;
        }
    }
}
